/**
 * 
 */
package neptune.manager.model.cluster;

import java.util.ArrayList;

import neptune.manager.model.topology.IPAddress;
import neptune.manager.model.topology.UndefinedControlInterfaceException;

/**
 * @author Roberto Bifulco [info@robertobifulco.it, robertobifulco.it]
 * @author Luigi Lorenzo Arpino [luigiarpino@yahoo.it]
 * 
 */
public class Cluster {

	/**
	 * I nodi fisici del cluster
	 */
	private ArrayList<PhysicalNode> nodes = new ArrayList<PhysicalNode>(0);

	/**
	 * Indirizzo della rete di controllo. E' in realta' un'informazione
	 * ridondante, poiche' ciascun nodo porta con se l'informazione del suo
	 * indirizzo di controllo. Lo scopo per cui viene definita e' per pure
	 * ragioni di controllo.
	 */
	private IPAddress controlNetAddress;

	/**
	 * Aggiunge un PhysicalNode al cluster
	 * 
	 * @param physicalNode
	 * @throws Exception 
	 */
	public void addPhysicalNode(PhysicalNode physicalNode) throws Exception 
	{
		// controllo che l'ip di controllo del nuovo physical node sia libero
		String ipAddress = physicalNode.getControlAddress().getAddress();
		if ( ipAddress.equalsIgnoreCase("") )
			throw new UndefinedControlInterfaceException(" Unable to add physical node : ip control address not defined ");
		for(PhysicalNode item : this.nodes)
		{
			if (item.getControlAddress().getAddress().equalsIgnoreCase(ipAddress) )
				throw new Exception(" Unable to add physical node : ip control address not free ");
		}
		this.nodes.add(physicalNode);
	}

	/**
	 * @return the controlNetAddress
	 */
	public IPAddress getControlNetAddress() {
		return controlNetAddress;
	}

	public PhysicalNode getNodeById(String pmId) 
	{
		for (PhysicalNode node : nodes) 
		{
			if (node.getId().equalsIgnoreCase(pmId) )
			{
				return node;
			}
		}
		return null;
	}

	/**
	 * Restituisce il nodo che ospita la virtual machine il cui identificativo
	 * e' passato come argomento, o restituisce null se non e' stato individuato
	 * alcun hoster sul cluster per quella data vm.
	 * 
	 * @param vmId
	 * @return
	 */
	public PhysicalNode getNodeHoster(String vmId) {
		for (PhysicalNode node : nodes) {
			if (node.isChildren(vmId))
				return node;
		}
		return null;
	}

	/**
	 * Restituisce un array con i nodi del cluster o null se non sono stati
	 * definiti nodi
	 * 
	 * @return the nodes
	 */
	public PhysicalNode[] getNodes() 
	{
		/*
		if (nodes.get(0) == null)
			return null;
		return (PhysicalNode[]) nodes.toArray(new PhysicalNode[1]);
		*/
		if ( this.nodes.size() == 0 )
		{
			return null;
		}
		else
		{
			return (PhysicalNode[]) nodes.toArray(new PhysicalNode[1]);
		}
	}

	/**
	 * @param controlNetAddress
	 *            the controlNetAddress to set
	 */
	public void setControlNetAddress(IPAddress controlNetAddress) {
		this.controlNetAddress = controlNetAddress;
	}

	/**
	 * @param nodes
	 *            the nodes to set
	 */
	public void setNodes(PhysicalNode[] nodes) {
		// TODO aggiungere una qualche procedura di verifica della realta'
		// delle impostazioni
		for (int j = 0; j < nodes.length; j++) {
			this.nodes.add(nodes[j]);
		}
	}

	/**
	 * Modifica i parametri di una macchina fisica
	 * 
	 * @param physicalNode
	 */
	public void editPhysicalNode(PhysicalNode physicalNode) {
		String id = physicalNode.getId();
		for (int i = 0; i < this.nodes.size(); i++) {
			PhysicalNode phyNode = this.nodes.get(i);
			if (phyNode.getId().equalsIgnoreCase(id)) {
				this.nodes.set(i, physicalNode);
				/*
				 * this.nodes.remove(i); this.nodes.add(physicalNode);
				 */
			}
		}
	}

	/**
	 * Rimuove una macchina fisica dal cluster
	 * 
	 * @param idPhysicalNode
	 * @return
	 */
	public boolean removePhysicalNode(String idPhysicalNode) {
		boolean isRemoved = false;
		for (int i = 0; i < this.nodes.size(); i++) {
			PhysicalNode phyNode = this.nodes.get(i);
			if (phyNode.getId().equalsIgnoreCase(idPhysicalNode)) {
				isRemoved = true;
				this.nodes.remove(i);
			}
		}
		return isRemoved;
	}
}
